﻿using Microsoft.Extensions.Hosting;
using Quartz;
using Quartz.Spi;

namespace PmSoft.Quartz;

public class QuartzHostedService : IHostedService
{
    private readonly ISchedulerFactory _schedulerFactory;
    private readonly IJobFactory _jobFactory;
    private readonly IEnumerable<JobDescriptor> _jobDescriptors;

    public QuartzHostedService(ISchedulerFactory schedulerFactory,
        IJobFactory jobFactory,
        IEnumerable<JobDescriptor> jobDescriptors)
    {
        _schedulerFactory = schedulerFactory;
        _jobDescriptors = jobDescriptors;
        _jobFactory = jobFactory;
    }

    public IScheduler Scheduler { get; private set; }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
        Scheduler.JobFactory = _jobFactory;

        foreach (var jobDescriptor in _jobDescriptors)
        {
            var job = CreateJob(jobDescriptor);
            var trigger = CreateTrigger(jobDescriptor);

            await Scheduler.ScheduleJob(job, trigger, cancellationToken);
        }

        await Scheduler.Start(cancellationToken);
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        IScheduler scheduler = Scheduler;
        await scheduler?.Shutdown(cancellationToken);
    }

    private ITrigger CreateTrigger(JobDescriptor schedule)
    {
        return TriggerBuilder
        .Create()
        .WithIdentity($"{schedule.JobType.FullName}.trigger")
        .WithCronSchedule(schedule.CronExpression)
        .WithDescription(schedule.CronExpression)
        .Build();
    }

    private IJobDetail CreateJob(JobDescriptor schedule)
    {
        var jobType = schedule.JobType;
        return JobBuilder
            .Create(jobType)
            .WithIdentity(jobType.FullName)
            .WithDescription(jobType.Name)
            .Build();
    }
}
